/**
 * 观察者模式
*/

#include <iostream>
#include <list>

using namespace std;

class Observer {  // 观察者抽象
public:
    virtual void Update(int) = 0;
};

class Subject {  // 被观察者抽象
public:
    virtual void Attach(Observer *) = 0;

    virtual void Detach(Observer *) = 0;

    virtual void Notify() = 0;
};

class ConcreteObserver1 : public Observer {  // 第一个观察者
public:
    ConcreteObserver1(Subject *pSubject) : m_pSubject(pSubject) {}

    void Update(int value) {
        cout << "ConcreteObserver1 get the update. New State:" << value << endl;
    }

private:
    Subject *m_pSubject;
};

class ConcreteObserver2 : public Observer {  // 第二个观察者
public:
    ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject) {}

    void Update(int value) {
        cout << "ConcreteObserver2 get the update. New State:" << value << endl;
    }

private:
    Subject *m_pSubject;
};

class ConcreteSubject : public Subject {  // 被观察者
public:
    void Attach(Observer *pObserver);

    void Detach(Observer *pObserver);

    void Notify();

    void SetState(int state) {
        m_iState = state;
    }

private:
    std::list<Observer *> m_ObserverList;
    int m_iState;
};

void ConcreteSubject::Attach(Observer *pObserver) { // 添加观察者
    m_ObserverList.push_back(pObserver);
}

void ConcreteSubject::Detach(Observer *pObserver) { // 删除观察者
    m_ObserverList.remove(pObserver);
}

void ConcreteSubject::Notify() {  // 通知观察者
    std::list<Observer *>::iterator it = m_ObserverList.begin();
    while (it != m_ObserverList.end()) {
        (*it)->Update(m_iState);
        ++it;
    }
}


int main() {
    // Create 被观察者
    ConcreteSubject *pSubject = new ConcreteSubject();

    // Create 观察者
    Observer *pObserver1 = new ConcreteObserver1(pSubject);
    Observer *pObserver2 = new ConcreteObserver2(pSubject);

    // 改变状态
    pSubject->SetState(2);

    // 注册观察者
    pSubject->Attach(pObserver1);
    pSubject->Attach(pObserver2);

    pSubject->Notify();// 通知观察者

    // 删除观察者
    pSubject->Detach(pObserver1);

    pSubject->SetState(3);
    pSubject->Notify();

    delete pObserver1;
    delete pObserver2;
